package com.nchu.student_score.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.nchu.student_score.dataObject.GradeResult;
import com.nchu.student_score.mapper.*;
import com.nchu.student_score.model.*;
import com.nchu.student_score.service.GradeService;
import com.nchu.student_score.util.Define;
import com.nchu.student_score.vo.ResultVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class GradeServiceImpl implements GradeService {
    @Autowired
    GradeTempMapper gradeTempMapper;
    @Autowired
    GradeMapper gradeMapper;
    @Autowired
    TeachTaskMapper taskMapper;
    @Autowired
    TeacherMapper teacherMapper;
    @Autowired
    CourseMapper courseMapper;
    @Autowired
    SubScoresMapper subScoresMapper;
    @Autowired
    AppealMapper appealMapper;
    @Autowired
    AdminMapper adminMapper;

    @Override
    public PageInfo<GradeTemp> getGradeList(GradeTemp input, Integer currPage) {//成绩查询界面 页面数据
        if(currPage == null) currPage = 1;
        PageHelper.startPage(currPage, Define.PAGE_SIZE);
        PageInfo<GradeTemp> pageInfo = new PageInfo<>(gradeTempMapper.selectByTeachIdAndClazz(input));
        List<GradeTemp> gradeTempList = pageInfo.getList();

        if(gradeTempList != null && gradeTempList.size() > 0){
            List<Grade> record = new ArrayList<>();
            for(GradeTemp gt : gradeTempList){//查询需要teachId 和 stuId集合
                Grade g = new Grade();
                g.setTeachId(gt.getTeachId());
                g.setStuId(gt.getStuId());
                record.add(g);
            }
            List<Grade> gradeList = gradeMapper.selectByTeachIdAndStuIds(record);//查出最终成绩
            Map<Integer,Grade> gradeMap = new HashMap<>();
            for(Grade g : gradeList){//为了将缓存和成绩一一对应，先将成绩存入map，再根据成绩缓存将其取出
                Integer stuId = g.getStuId();
                gradeMap.put(stuId,g);//按照stuId将学生成绩存入
            }

            for(GradeTemp gt : gradeTempList){//按照stuId将学生最终成绩取出
                gt.setTotalScore(gradeMap.get(gt.getStuId()).getScore());
            }
            pageInfo.setList(gradeTempList);
        }
        return pageInfo;
    }

    @Override
    public ResultVo<GradeTemp> getGradeExcel(GradeTemp input) {//成绩查询界面 导出数据
        ResultVo<GradeTemp> resultVo = new ResultVo<>();
        List<GradeTemp> gradeTempList = gradeTempMapper.selectByTeachIdAndClazz(input);//查出成绩缓存

        if(gradeTempList != null && gradeTempList.size() > 0){
            List<Grade> record = new ArrayList<>();
            for(GradeTemp gt : gradeTempList){//查询需要teachId 和 stuId集合
                Grade g = new Grade();
                g.setTeachId(gt.getTeachId());
                g.setStuId(gt.getStuId());
                record.add(g);
            }
            List<Grade> gradeList = gradeMapper.selectByTeachIdAndStuIds(record);//查出最终成绩
            Map<Integer,Grade> gradeMap = new HashMap<>();
            for(Grade g : gradeList){//为了将缓存和成绩一一对应，先将成绩存入map，再根据成绩缓存将其取出
                Integer stuId = g.getStuId();
                gradeMap.put(stuId,g);//按照stuId将学生成绩存入
            }

            for(GradeTemp gt : gradeTempList){//按照stuId将学生最终成绩取出
                gt.setTotalScore(gradeMap.get(gt.getStuId()).getScore());
            }
        }
        resultVo.setList(gradeTempList);
        resultVo.setStatus(0);
        return resultVo;
    }

    @Override
    public ResultVo<GradeResult> getStuGradeDetails(GradeResult input) {//查看一门成绩详情
        ResultVo<GradeResult> resultVo = new ResultVo<>();
        //查出自己的该课程的所有子成绩
        input.setSubScoresList(subScoresMapper.selectByTaskIdAndStuId(input));
        //查出自己的各项成绩组成的得分
        input.setGradeTemp(gradeTempMapper.selectByTaskIdAndStuId(input));
        //查出自己的申诉记录
        input.setAppealList(appealMapper.selectAppealByGradeId(input.getGradeId()));
        for(Appeal a : input.getAppealList()){//将管理员的姓名加入
            if(a.getAdminId() != null)
                a.setAdminName(adminMapper.selectByPrimaryKey(a.getAdminId()).getAdminName());
        }

        //查出该安排下所有成绩 用于计算排名和比例 已隐藏学生学号
        List<Grade> gradeList = gradeMapper.selectByTeachId(input.getTeachId());

        int total = gradeList.size();//总人数
        int ranking = 1;//排名
        int pct;//超过的百分比
        for(Grade g : gradeList){//遍历成绩
            if(g.getScore() > input.getScore()){//有人的成绩比查询者更高
                ranking++;
            }
        }
        for(pct = 40;pct < 100;pct++){//计算出该学生超过的人数比例
            if(ranking > Math.ceil(total * (100 - pct) / 100.0)){
                break;
            }
        }
        if(pct == 100 && ranking > 1) pct = 99;//只有第1名才能超过100%

        //成绩合格且处于前60%
        if(pct > 40 && input.getScore() >= input.getTeachTask().getPassingScore()){
            input.setRanking("你的排名 : " + ranking + " , 总人数 : " + total);
            if(pct > 90 && input.getScore() >= (input.getTeachTask().getFullScore() * 0.85)){
                //超过90的同学且成绩>=总分的85%
                input.setOverPct("祝贺你 , 你已经超过了 " + pct + " % 的同学 !");
                input.setSuggest("你的成绩十分优异 , 请继续保持 !");
            }
            else if(pct > 80){//前20%
                input.setOverPct("恭喜你 , 你已经超过了 " + pct + " % 的同学 !");
                input.setSuggest("你的成绩优秀 , 请继续努力 !");
            }
            else if(pct > 60){//前40%
                input.setOverPct("你已经超过了 " + pct + " % 的同学");
                input.setSuggest("你的成绩良好 , 请继续努力 !");
            }
            else{//前60%
                input.setOverPct("你已经超过了 " + pct + " % 的同学");
                input.setSuggest("你的成绩中等 , 相信在你的身上还藏着更大的潜力 !");
            }
        }
        else{
            if(pct > 40){//前60%但是没有合格
                input.setRanking("你的排名 : " + ranking + " , 总人数 : " + total);
                input.setOverPct("你已经超过了 " + pct + " % 的同学");
                input.setSuggest("你的成绩并不落后 , 但似乎没有达到老师的要求 , 请继续努力 !");
            }
            else if(input.getScore() >= input.getTeachTask().getPassingScore()){//成绩合格但排名落后
                input.setRanking("你的排名 : >= " + (int) Math.ceil(total * 0.6) + " , 总人数 : " + total);
                input.setOverPct("你超过了 <= 40 % 的同学");
                input.setSuggest("你的成绩已经达到了老师的要求 , 但排名稍微落后了 , 请继续努力 !");
            }
            else{
                input.setRanking("你的排名 : >= " + (int) Math.ceil(total * 0.6) + " , 总人数 : " + total);
                input.setOverPct("你超过了 <= 40 % 的同学");
                input.setSuggest("尽管你现在落后了 , 但是请你不要放弃 , 请继续加油 !");
            }
        }

        resultVo.setObj(input);
        resultVo.setStatus(0);
        return resultVo;
    }

    @Override
    public PageInfo<GradeResult> getGradesListByStuId(GradeResult input, Integer currPage) {
        if(currPage == null) currPage = 1;

        if(input.getStuId() == null)//没有学生id无法查询
            return null;

        PageHelper.startPage(currPage, Define.STU_GRADES_PAGE_SIZE);
        PageInfo<GradeResult> pageInfo = new PageInfo<>(gradeMapper.getGradesList(input));

        List<GradeResult> list = pageInfo.getList();//取出分页查询结果
        if(list == null || list.size() == 0){//结果为空直接返回
            return pageInfo;
        }

        for(GradeResult g : list){//依次查询课程安排 因为每次只有3个 故采用可能效率较低但很简单的方法
            g.setTeachTask(taskMapper.selectByPrimaryKey(g.getTeachId()));
        }

        //考虑到教师的人数远远没有教学安排的数量多，故直接查询所有数据再进行处理
        List<Teacher> teacherList = teacherMapper.selectAll();
        for (Teacher t : teacherList) {//插入教师
            for (GradeResult g : list) {//因每次查询的成绩数量只有几个，故时间复杂度为n^2也无妨
                if (Objects.equals(t.getTeacherId(), g.getTeachTask().getTeacherId())) {
                    t.setTeacherPassword(null);//保护教师的密码安全
                    t.setTeacherIdCard(null);//保护教师的隐私
                    t.setTeacherPhone(null);//保护教师的隐私
                    g.setTeacher(t);
                }
            }
        }

        //考虑到课程的数量远远没有教学安排多，故直接查询所有数据再进行处理
        List<Course> courseList = courseMapper.findCourseList(new Course());
        for(Course c:courseList){//插入课程
            for(GradeResult g:list){//因每次查询的成绩数量只有几个，故时间复杂度为n^2也无妨
                if(Objects.equals(c.getCourseId(), g.getTeachTask().getCourseId())){
                    g.setCourse(c);
                }
            }
        }

        pageInfo.setList(list);
        return pageInfo;
    }

    @Override
    public ResultVo<GradeTemp> submitStudentGrades(TeachTask input, String submitType) {//提交成绩
        ResultVo<GradeTemp> resultVo = new ResultVo<>();

        if(! (submitType.equals("try") || submitType.equals("confirm"))){
            resultVo.setStatus(1);
            resultVo.setMessage("未知的提交请求!");
            return resultVo;
        }

        TeachTask task = taskMapper.selectByPrimaryKey(input.getTeachId());
        if(task == null || task.getTeachState() != 1){//教学安排不存在或状态不为进行中
            resultVo.setStatus(2);
            resultVo.setMessage("当前教学安排无法提交!");
            return resultVo;
        }

        List<GradeTemp> tempList = gradeTempMapper.selectByTeachId(task.getTeachId());//查出的成绩缓存
        List<Grade> gradeList = new ArrayList<>();//提交的成绩单
        StringBuilder resultMessage = new StringBuilder("检测到学号为: ");//填写不完整返回消息
        int count = 0;//填写不完整计数
        for(GradeTemp temp:tempList){
            boolean check = false;
            if(task.getUsualPct() > 0 && temp.getUsualScore() == null){//填写不完整检验
                check = true;
                temp.setUsualScore(0);
            }
            if(task.getExpPct() > 0 && temp.getExpScore() == null){//填写不完整检验
                check = true;
                temp.setExpScore(0);
            }
            if(task.getMidPct() > 0 && temp.getMidScore() == null){//填写不完整检验
                check = true;
                temp.setMidScore(0);
            }
            if(task.getFinalPct() > 0 && temp.getFinalScore() == null){//填写不完整检验
                check = true;
                temp.setFinalScore(0);
            }
            if(task.getOtherPct() > 0 && temp.getOtherScore() == null){//填写不完整检验
                check = true;
                temp.setOtherScore(0);
            }
            if(check){
                resultMessage.append(temp.getStuId()).append(" ");//记录填写不完整的学号
                count++;
            }
            if(submitType.equals("confirm")){//确认提交才需要生成成绩单
                double score = 0.0;
                if(task.getUsualPct() > 0)
                    score += task.getUsualPct() * temp.getUsualScore();
                if(task.getExpPct() > 0)
                    score += task.getExpPct() * temp.getExpScore();
                if(task.getMidPct() > 0)
                    score += task.getMidPct() * temp.getMidScore();
                if(task.getFinalPct() > 0)
                    score += task.getFinalPct() * temp.getFinalScore();
                if(task.getOtherPct() > 0)
                    score += task.getOtherPct() * temp.getOtherScore();
                Grade grade = new Grade();
                grade.setStuId(temp.getStuId());
                grade.setTeachId(task.getTeachId());
                grade.setScore((int)Math.ceil(score/100));//成绩向上取整
                gradeList.add(grade);
            }
        }
        resultMessage.append("的成绩填写不完整，确认提交？");

        if(submitType.equals("confirm")){
            gradeMapper.insertAll(gradeList);//提交成绩
            task.setTeachState(2);
            taskMapper.updateByPrimaryKey(task);//更新教学安排状态
            resultVo.setMessage("提交成绩成功!");
        }
        else{
            if(count > 0)
                resultVo.setMessage(String.valueOf(resultMessage));
            else
                resultVo.setMessage("所有学生的成绩均填写完毕，确认提交？");
        }
        resultVo.setStatus(0);

        return resultVo;
    }

    @Override
    public PageInfo<GradeTemp> getGradeTempList(GradeTemp input, Integer currPage) {
        if(currPage == null) currPage = 1;
        PageHelper.startPage(currPage, Define.PAGE_SIZE);
        return new PageInfo<>(gradeTempMapper.selectByTeachIdAndClazz(input));
    }

    @Override
    public ResultVo<GradeTemp> getGradeTempsExcel(GradeTemp input) {
        ResultVo<GradeTemp> resultVo = new ResultVo<>();
        resultVo.setList(gradeTempMapper.selectByTeachIdAndClazz(input));
        resultVo.setStatus(0);
        return resultVo;
    }

    @Override
    public ResultVo<GradeTemp> uploadGradeTempsExcel(List<GradeTemp> list) {
        ResultVo<GradeTemp> resultVo = new ResultVo<>();
        for(GradeTemp t:list){
            if(t != null && t.getTeachId() != null && t.getStuId() != null)
                gradeTempMapper.updateByTeachIdAndStuId(t);
        }
        resultVo.setStatus(0);
        return resultVo;
    }

    @Override
    public ResultVo<GradeTemp> saveGradeTemps(List<GradeTemp> tempList) {//暂存成绩缓存
        ResultVo<GradeTemp> resultVo = new ResultVo<>();
        for(GradeTemp t:tempList){//由于update语句采用各种批量操作实质也是逐条更新，故使用最简便原始的方法
            gradeTempMapper.updateByPrimaryKey(t);
        }
        resultVo.setStatus(0);
        return resultVo;
    }
}
